package net.hands.ado.db;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.hands.ado.ADOException;
import net.hands.ado.db.annotations.Table;
import net.hands.ado.db.jdbc.DatabaseMeta;
import net.hands.ado.db.jdbc.IJdbcProvider;
import net.hands.ado.db.jdbc.dialect.Dialect;
import net.hands.common.ClassUtils.IScanResourcesCallback;
import net.hands.common.ClassUtils.ScanClassResourcesCallback;
import net.hands.common.StringUtils;
import net.hands.common.trans.ITransactionCallback;

public class DBTablesFactory {

	static final String ERROR = " \r result : error";
	// static final String SUCCEED = "\r result : succeed";
	/**
	 * 信息名称集合
	 */
	private static Map<Class<?>, DBTable> tables = new HashMap<Class<?>, DBTable>();

	/**
	 * 扫描所有表对象
	 * 
	 * @return
	 */
	public static IScanResourcesCallback getDBTablesCallback() {
		return new ScanClassResourcesCallback() {
			@Override
			public void doResources(final String filepath,
					final boolean isDirectory) {
				// 文件路径是否是资源文件
				final Class<?> oClass = loadClass(filepath);
				if (oClass != null) {
					addDBTable(oClass);
				}
			}
		};

	};

	public static DBTable getDBTable(final Class<?> etable) {
		return tables.get(etable);
	}

	public static void addDBTable(final Class<?> etable) {
		if (etable.isAnnotationPresent(Table.class)) {
			if (tables.get(etable) == null) {
				tables.put(etable, new DBTable(etable));
			}

		}
	}

	public static void remove(final Class<?> etable) {
		tables.remove(etable);
	}

	public static void clear() {
		tables.clear();
	}

	/**
	 * 删除表
	 */
	public static int droptETest(IJdbcProvider provider, DBTable dbTable) {
		Dialect dialect = provider.getJdbcDialect();
		StringBuilder sb = new StringBuilder();
		sb.append(dbTable.sqlDropTable(dialect));
		return provider.doUpdate(new SQLValue(sb.toString()));
	}

	/**
	 * 删除唯一
	 */
	public static void dropUnique(IJdbcProvider provider, DBTable dbTable) {
		Dialect dialect = provider.getJdbcDialect();
		String[] uniqueArr = dbTable.sqlDropUniques(dialect);
		for (String unique : uniqueArr) {
			try {
				provider.doUpdate(new SQLValue(unique));
			} catch (Exception e) {
				throw DBException.of(unique + "ERROR");
			}
		}
	}

	/**
	 * 删除索引
	 */
	public static void dropIndex(IJdbcProvider provider, DBTable dbTable) {
		Dialect dialect = provider.getJdbcDialect();
		String[] uniqueArr = dbTable.sqlDropIndex(dialect);
		for (String unique : uniqueArr) {
			try {
				provider.doUpdate(new SQLValue(unique));
			} catch (Exception e) {
				throw DBException.of(unique + ": ERROR");
			}
		}
	}

	/**
	 * 导表
	 * 
	 * @param provider
	 * @param dbTable
	 */
	protected static void exportTable(final IJdbcProvider provider,
			final DBTable dbTable) {

		provider.doExecuteTransaction(new ITransactionCallback<Integer>() {
			@Override
			public Integer onTransactionCallback() throws ADOException {

				final Dialect dialect = provider.getJdbcDialect();
				final String sql = dbTable.sqlCreateTable(dialect);
				try {
					provider.doUpdate(sql);
					String[] uniqueArr = dbTable.sqlAddUniques(dialect);
					for (String unique : uniqueArr) {
						try {
							provider.doUpdate(unique);
						} catch (Exception e) {
							throw DBException.of(unique + ": ERROR");
						}
					}
					// 创建索引
					String[] indexArr = dbTable.sqlAddIndexs(dialect);
					for (String index : indexArr) {
						try {
							provider.doUpdate(index);
						} catch (Exception e) {
							throw DBException.of(index + ": ERROR");
						}
					}
				} catch (Exception e) {
					throw DBException.of(sql + ERROR);
				}

				return 0;

			}
		}, null);
	}

	public static void exportTables(IJdbcProvider provider) {
		exportTables(provider, null);
	}

	/**
	 * 多数据源导入
	 * 
	 * @param defProvider
	 * @param providers
	 */
	public static void exportTables(IJdbcProvider defProvider,
			IJdbcProvider[] providers) {
		if (tables.size() > 0) {
			if (providers != null && providers.length > 0) {
				for (final DBTable dbTable : tables.values()) {
					for (IJdbcProvider provider : providers) {
						if (StringUtils.hasText(dbTable.getUrl())) {
							final String _url = provider.getDatabaseMeta()
									.getUrl();
							if (_url == null
									|| !_url.endsWith(dbTable.getUrl())) {
								continue;
							}
							exportTable(provider, dbTable);

						} else {
							exportTable(defProvider, dbTable);
						}
					}
				}
			} else {
				for (final DBTable dbTable : tables.values()) {
					exportTable(defProvider, dbTable);
				}

			}
		} else {
			throw DBException.of("not found dbtable");
		}

	}

	/**
	 * 更新表
	 * 
	 * @param provider
	 * @param dbTable
	 */
	protected static void updateTable(final IJdbcProvider provider,
			final DBTable dbTable, final Boolean isDropColumn) {
		final DatabaseMeta meta = provider.getDatabaseMeta();
		DBTable table = meta.getDBTable(dbTable.getName());// 数据库表实体
		if (table == null) {
			exportTable(provider, dbTable);
		} else {
			final Dialect dialect = provider.getJdbcDialect();
			final Map<String, DBColumn> dbColumns = dbTable.getColumns();
			final Map<String, DBColumn> columns = table.getColumns();
			// 新增字段集合
			final List<String> sqlColumns = new ArrayList<String>();

			for (String key : dbColumns.keySet()) {// 添加字段
				if (!columns.containsKey(key)) {
					sqlColumns.add(dbTable.sqlAddColumn(dialect,
							dbColumns.get(key)));
				}
			}
			if (isDropColumn) {
				for (String key : columns.keySet()) {
					if (!dbColumns.containsKey(key)) {
						sqlColumns.add(dbTable.sqlDropColumn(dialect,
								columns.get(key)));
					}
				}
			}
			if (sqlColumns.size() > 0) {
				for (String sqlColumn : sqlColumns) {
					try {
						provider.doUpdate(sqlColumn);
					} catch (Exception e) {
						throw DBException.of(sqlColumn + ERROR);
					}

				}
			}

		}
	}

	public static void updateTables(IJdbcProvider provider) {
		updateTables(provider, null, true);
	}

	public static void updateTables(IJdbcProvider provider,
			final Boolean isDropColumn) {
		updateTables(provider, null, isDropColumn);
	}

	/**
	 * 更新数据库
	 */
	public static void updateTables(IJdbcProvider defProvider,
			IJdbcProvider[] providers, final Boolean isDropColumn) {
		if (tables.size() > 0) {
			if (providers != null && providers.length > 0) {
				for (final DBTable dbTable : tables.values()) {
					for (IJdbcProvider provider : providers) {
						if (StringUtils.hasText(dbTable.getUrl())) {
							final String _url = provider.getDatabaseMeta()
									.getUrl();
							if (_url == null
									|| !_url.endsWith(dbTable.getUrl())) {
								continue;
							}
							updateTable(provider, dbTable, isDropColumn);
						} else {
							updateTable(defProvider, dbTable, isDropColumn);
						}
					}
				}
			} else {
				for (final DBTable dbTable : tables.values()) {
					updateTable(defProvider, dbTable, isDropColumn);
				}
			}

		}

	}

}
